package org.example.demo_ottery.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import org.example.demo_ottery.common.errorcode.ServiceErrorCodeConstants;
import org.example.demo_ottery.common.exception.ServiceException;
import org.example.demo_ottery.common.utils.JWTUtil;
import org.example.demo_ottery.common.utils.RegexUtil;
import org.example.demo_ottery.controller.param.ShortMessageLoginParam;
import org.example.demo_ottery.controller.param.UserLoginParam;
import org.example.demo_ottery.controller.param.UserPasswordLoginParam;
import org.example.demo_ottery.controller.param.UserRegisterParam;
import org.example.demo_ottery.dao.dataobject.Encrypt;
import org.example.demo_ottery.dao.dataobject.UserDO;
import org.example.demo_ottery.dao.mapper.UserMapper;
import org.example.demo_ottery.service.UserService;
import org.example.demo_ottery.service.VerificationCodeService;
import org.example.demo_ottery.service.dto.UserDTO;
import org.example.demo_ottery.service.dto.UserLoginDTO;
import org.example.demo_ottery.service.dto.UserRegisterDTO;
import org.example.demo_ottery.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;

    @Autowired
    VerificationCodeService verificationCodeService;

    @Override
    public UserRegisterDTO register(UserRegisterParam Param) {
        checkRegisterInfo(Param);
        UserDO userDO=new UserDO();
        userDO.setUserName(Param.getName());
        userDO.setIdentity(Param.getIdentity());
        userDO.setEmail(Param.getMail());
        userDO.setPhoneNumber(new Encrypt(Param.getPhoneNumber()));
        if(StringUtils.hasText(Param.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(Param.getPassword()));
        }
        userMapper.insert(userDO);

        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO = null;
        if(param instanceof UserPasswordLoginParam loginParam) {
            //密码登录
            userLoginDTO = loginByUserPassword(loginParam);
        } else if (param instanceof ShortMessageLoginParam loginParam) {
            //验证码登录
            userLoginDTO = loginByShortMessage(loginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        return userLoginDTO;
    }

    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String identityString = null == identity ? null : identity.name();
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList = userDOList.stream()
                .map(userDO ->{
                    UserDTO userDTO = new UserDTO();
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setUserId(userDO.getId());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setEmail(userDO.getEmail());
                    return userDTO;
                        }).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 验证码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {
        if(!RegexUtil.checkMobile(loginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //获取用户数据
        UserDO userDO = userMapper.selectByPhoneNumber(
                new Encrypt(loginParam.getLoginMobile()));
        if(null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(userDO.getIdentity())
        &&!userDO.getIdentity().equalsIgnoreCase(loginParam.getVerificationCode())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验验证码
        String code = verificationCodeService.getVerificationCode(
                loginParam.getLoginMobile());

        if (!loginParam.getVerificationCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }

        // 塞入返回值（JWT）
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    /**
     * 密码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO = null;
        if(RegexUtil.checkMobile(loginParam.getLoginName())) {
            //手机号登录
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        } else if (RegexUtil.checkMail(loginParam.getLoginName())) {
            //邮箱登录
            userDO = userMapper.selectByMail(loginParam.getLoginName());
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }
        //校验登录信息
        if(null==userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(userDO.getIdentity())
                &&!loginParam.getMandatoryIdentity()
                .equalsIgnoreCase(userDO.getIdentity())) {
            //校验身份信息不通过
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtil.sha256Hex(loginParam.getPassword())
                .equals(userDO.getPassword())) {
            //校验密码不通过
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //生成jwt
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    private void checkRegisterInfo(UserRegisterParam userRegisterParam) {
        /**
         * 注册信息为空
         */
        if(null == userRegisterParam) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        //检验邮箱格式
        if(!RegexUtil.checkMail(userRegisterParam.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //检验手机号格式
        if(!RegexUtil.checkMobile(userRegisterParam.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //校验身份信息
        if(null == UserIdentityEnum.forName(userRegisterParam.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //管理员密码不能为空
        if(userRegisterParam.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(userRegisterParam.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //校验密码，至少六位
        if(StringUtils.hasText(userRegisterParam.getPassword())
                &&!RegexUtil.checkPassword(userRegisterParam.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //检验邮箱是否被使用
        if(checkMailUsed(userRegisterParam.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }
        //校验手机号是否被使用
        if(checkPhoneNumberUsed(userRegisterParam.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int count = userMapper.countByPhoneNumber(new Encrypt(phoneNumber));
        return count > 0;
    }

    private boolean checkMailUsed(String mail) {
        int ret=userMapper.countByMail(mail);
        return ret > 0;
    }
}
